Compilation is that process that takes place in the computer in which a computer program written in a human readable programming language is translated, through a series of steps of lexical analysis, parsing and semantic analysis, into binary code capable of execution by a data processing system. Commonly, the compiler itself produces a number of compilation or translation units that are linked into the final output, an executable file, by a linker or linker/loader.
C++ is an object-oriented programming language in which programs are created using abstractions and constructs to create user-defined classes for defining the methods and variables for a particular type of object. All objects of a particular class are identical in form and behaviour but contain different data on their variables.
The C++ language also provides templates, which define families of classes and functions that are structurally identical but contain different kinds of data in their variables or function parameters. Each family is specified by a template declaration, and each member of the family is called an instantiation. Instantiations are created by the compiler.
A template declaration has two parts: the template parameters, and the class or function, written using the template parameter names. For example, this class template represents a list:
______________________________________ template&lt;class ElementType&gt; class List: public SimpleList&lt;ElementType&gt; { // Add and remove elements from the list // void add(ElementType&); void remove(ElementType&); // Obtain the last element of the list. This causes a ListViewer&lt;ElementType&gt; // template to be instantiated. // ElementType last( ) { ListViewer&lt;ElementType&gt;it(*this); return it.last( ); } ______________________________________
This template has a single template parameter, "ElementType", is a subclass of another templatized list, SimpleList, and has a function body that uses a third template, called ListViewer. The template is instantiated by specifying a set of template arguments that match the parameters, e.g., List&lt;int&gt;. Instantiation creates a new class, called, "List&lt;int&gt;", with ElementType replaced by int. This instantiated class behaves like a normal (non-template) class in post-parse phases, like type and overloading analysis.
In the course of instantiating a template, it may be necessary to instantiate others. In this case, before List&lt;int&gt; is instantiated, SimpleList&lt;int&gt; must be instantiated, and before the function body List&lt;int&gt;::viewer( ) can be instantiated, ListViewer&lt;int&gt; must be instantiated. The instantiation of SimpleList&lt;int&gt; and ListViewer&lt;int&gt; are respectively antecedents of (the instantiations of) List&lt;int&gt; and the body of List&lt;int&gt;::viewer( ). Similarly, the instantiation of List&lt;int&gt; is a dependent of the instantiation of SimpleList&lt;int&gt;. Because the programmer has not explicitly requested antecedent instantiations, error messages about antecedent instantiations must include information tracing back the dependent instantiations so that the programmer can understand the origin of the errors.
Current C++ compilers generate poor error diagnostics for templates. Cascading template instantiation error messages (or "traceback" messages) are not generated by most compilers, and even those error messages that are generated by current compilers are difficult to decipher.
One reason for this is that most compilers perform antecedent instantiations by recursively invoking the compiler. This means that the compiler suspends the instantiation currently being processed while the antecedent instantiation is being done.
If a compilation error occurs while performing the antecedent instantiation it can be difficult to produce additional error messages that relate that error to the dependent instantiation. For example, the following has a syntax error because member type Base&lt;int&gt;::ElementType cannot be used as a base class:
template&lt;class T&gt;class Base {typedef T ElementType; }; PA0 template&lt;class T&gt;class Derived: public Base&lt;T&gt;::ElementType { }; PA0 Derived&lt;int&gt;derived;
The antecedent error "Base&lt;T&gt;::ElementType is not a class" is not helpful without an additional error message "Error while instantiating Derived&lt;int&gt;". It is difficult to synthesize these error messages from a recursive invocation of the compiler.
Another drawback to recursive antecedent instantiation is the requirement for unbounded memory because of the recursion. For example, the following defines an array inductively: an array of dimension n is defined as a sub-class of an array of dimension n-1, and an instantiation of Array&lt;100&gt; would invoke the compiler 100 times recursively.
______________________________________ // Define an array template recursively. // template&lt;int I&gt; class Array: public Array&lt;i-1&gt; { int E; }; // The base case. // template&lt; &gt; class Array&lt;0&gt; { }; ______________________________________
In addition to the foregoing, some current compilers delay the creation of error messages until the translation unit has been completed, or even until the entire program is linked. This makes it difficult to match error messages with source code fragments. The time lag between compilation and linking in conventional compilers exacerbates this problem.